package com.je.ldap;

import com.je.core.util.WebUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * LDAP认证工具类
 * <p>
 * LDAP_URL：LDAP服务地址 ldap://127.0.0.1:389
 * LDAP_BASE：LDAP用户所属位置 dc=maxcrc,dc=com
 * LDAP_MANAGER_DN：LDAP管理员DN cn=Manager,dc=maxcrc,dc=com
 * LDAP_MANAGER_SECRET：LDAP管理员密码
 * LDAP_SEARCH_FILTER：LDAP查询过滤条件，支持username变量。如 (mobile=#username#)
 * LDAP_JEPAAS_RELATION：LDAP用户与JEPAAS用户属性对应关系。如 USERCODE-mobile 表示LDAP用户的mobile属性值对应的是JEPAAS用户的USERCODE
 *
 * @author wangmm
 * @date 2021/2/8
 */
public class LdapUtil {

    private static LdapTemplate ldapTemplate;

    /**
     * 获取系统变量中的配置
     *
     * @return LDAP配置信息
     */
    private static LdapContextSource contextSource() {

        LdapContextSource contextSource = new LdapContextSource();
        // ldap://127.0.0.1:389
        contextSource.setUrl(WebUtils.getVariable("LDAP_URL"));
        // dc=maxcrc,dc=com
        contextSource.setBase(WebUtils.getVariable("LDAP_BASE"));
        // cn=Manager,dc=maxcrc,dc=com
        contextSource.setUserDn(WebUtils.getVariable("LDAP_MANAGER_DN"));
        // secret
        contextSource.setPassword(WebUtils.getVariable("LDAP_MANAGER_SECRET"));
        contextSource.afterPropertiesSet();
        contextSource.setPooled(true);
        return contextSource;
    }

    /**
     * 获取ldapTemplate
     *
     * @return ldapTemplate
     */
    public static LdapTemplate getLdapTemplate() {
        if (null == ldapTemplate) {
            ldapTemplate = new LdapTemplate(contextSource());
        }
        return ldapTemplate;
    }

    /**
     * 重置ldapTemplate，会在清空全部缓存后调用(勿删)
     */
    public static void reInit() {
        ldapTemplate = null;
    }

    /**
     * 校验LDAP用户密码(勿删)
     * <p>
     * 在/rbac/login/login接口中调用
     *
     * @param username LDAP用户标识
     * @param password LDAP用户密码
     * @return 查找jepaas用户的where条件
     */
    public static Map<String, Object> check(String username, String password) {
        //LDAP模板类
        LdapTemplate ldapTemplate = getLdapTemplate();
        //LDAP查询过滤器
        String filter = WebUtils.getVariable("LDAP_SEARCH_FILTER");

        //查找LDAP用户
        List<DirContextAdapter> list = ldapTemplate.search("", filter.replaceAll("#username#", username), (Object ctx) -> (DirContextAdapter) ctx);
        //校验查询结果
        if (list.size() != 1) {
            throw new RuntimeException("LDAP User not found or not unique");
        }
        DirContextAdapter contextAdapter = list.get(0);

        //校验密码
        boolean authenticate = ldapTemplate.authenticate(contextAdapter.getDn(), "(objectclass=person)", password);
        if (!authenticate) {
            throw new RuntimeException("LDAP user invalid password");
        }
        //获取对应关系
        String relationStr = WebUtils.getVariable("LDAP_JEPAAS_RELATION");
        if (StringUtils.isBlank(relationStr)) {
            throw new RuntimeException("LDAP_JEPAAS_RELATION not found");
        }
        //设置条件
        Map<String, Object> condition = new HashMap<>();
        String[] relations = relationStr.split(",");
        for (String relation : relations) {
            String[] codes = relation.split("-");
            condition.put(codes[0], contextAdapter.getStringAttribute(codes[1]));
        }
        //返回查询条件
        return condition;
    }

}
